Skip to content

docs: improve how the repository presents itself - #113

Merged
vishr merged 6 commits into
mainfrom
docs/repository-presentation
Aug 24, 2026
Merged

docs: improve how the repository presents itself#113
vishr merged 6 commits into
mainfrom
docs/repository-presentation

Conversation

@vishr

@vishr vishr commented Aug 24, 2026

Copy link
Copy Markdown
Member

What this changes

Three gaps in how the repository meets someone who has just found it.

Issue and pull request templates. .github/ held only workflows, so a bug report could arrive without a version, a target host, or the plan output that shows the discrepancy, and a proposal could arrive without saying whether it widens the one-application, one-host scope. config.yml turns off blank issues and points security reports at SECURITY.md.

A social preview card, and an og:image. Links to this repository unfurled as a generic grey box. Separately, Starlight emits twitter:card: summary_large_image but never an og:image to pair with it, so links to onebox.run unfurled as an empty large card — the worst of both. site/src/components/Head.astro now emits og:image, its dimensions, an alt line, and twitter:image.

The card is generated: just social-card renders docs/media/social-card.typ at 960pt × 480pt, exactly 1280 × 640 px at 96 ppi. The recipe pins typst 0.15.1, requires IBM Plex Mono on ONEBOX_FONT_PATH and fails when the face is missing — typst only warns and exits 0, so the alternative is silently shipping a card set in a fallback face — and installs the PNG from a temporary directory only once the render is known good. The mark is read from site/public/favicon.svg rather than copied, so a revised favicon reaches the card.

CI has no font path and cannot re-render the card, so the gate does the part it honestly can: site-build now runs site/scripts/check-social-card.mjs, which asserts every built page carries an og:image, that the target is actually in dist/, and that its real PNG dimensions match the hand-typed og:image:width/height.

A comparison table. The README never contained the words Docker Compose, Kamal, Dokku, CapRover, Coolify, Ansible, Kubernetes, or Terraform, which is what someone types when they are shopping in this space. Each row states the boundary difference rather than a feature score, and the Kubernetes row says outright what Onebox gives up.

Still manual after this

The GitHub social preview image is uploaded through Settings → General → Social preview; there is no API for it. Use site/public/social-card.png.

What I ran

just check — passes, including site-build. Verified in site/dist/index.html that the built head carries og:image pointing at https://onebox.run/social-card.png and that the asset is emitted. Exercised just social-card against an empty font directory (fails, committed PNG untouched) and a real one (re-renders byte-identically), and check-social-card.mjs against a missing asset and a wrong-sized one.

Did not run just e2e: nothing here touches the binary or the deployment path.

vishr and others added 6 commits August 23, 2026 21:21
Three gaps that all cost the project the same thing — someone finds Onebox
and leaves without understanding what it is or how to engage with it.

Issue and pull request templates. There were none, so a bug report arrived
without a version, a target host, or the plan output that shows the
discrepancy, and a proposal arrived without saying whether it widens the
one-application, one-host scope. The templates ask for exactly what a
maintainer needs on the first round trip, and the config points security
reports at SECURITY.md rather than a public issue.

A social preview card. GitHub and every chat client showed a generic grey
box for links to this repository. Worse, Starlight emits
`twitter:card: summary_large_image` and never an image to pair with it, so
links to onebox.run unfurled as an empty large card. The card is rendered
from `docs/media/social-card.typ`, and the site serves it as its og:image.

A comparison table. The README never named Docker Compose, Kamal, Dokku,
Coolify, Ansible, or Kubernetes, which are the words someone uses when they
are looking for a tool in this space. Each row states the boundary
difference rather than a feature score, and the Kubernetes row says plainly
what Onebox gives up.

Ran `just check`: passes. Did not run `just e2e`; nothing here touches the
binary or the deployment path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review of the first commit found the card carrying two failure modes that
nothing would report.

The mark was copied into `docs/media/social-card-mark.svg`, byte-identical
to the one in `site/public/favicon.svg` and connected to it by nothing. The
favicon comment records that four earlier drafts of that mark died before
this one; the next revision would have reached the site and left the card —
the most-seen surface — drawing a retired logo. Typst reads the favicon
directly, so the copy is gone and the render is unchanged, pixel for pixel.

The PNG had no generator and no check. `just social-card` renders it, and
does the part a hand-typed command cannot: typst warns about an unknown font
family and still exits 0, so it verifies the font was actually found and
fails when it was not. The typst version is pinned because another release
re-lays out every glyph. CI has no font path and so cannot re-render, but
`site-build` now asserts the committed PNG exists and matches the dimensions
the head advertises — the previous commit emitted `og:image` unconditionally,
so renaming the asset would have left every page pointing at a 404.

Also corrects a comment from the previous commit: `astro.config.mjs` sets
`site` unconditionally, so the fallback is not a configuration this
repository ships.

Ran `just check`: passes. Exercised `just social-card` against an empty font
directory (fails, as intended) and a real one (renders a card identical to
the committed PNG), and `check-social-card.mjs` against a missing asset and
a wrong-sized one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two parity fixes with the same change in the Fanout repository, where the
review that prompted them ran.

`just social-card` wrote straight to `site/public/social-card.png` and only
then checked whether typst had fallen back to a substitute face. It failed
correctly, but the wrong card was already on disk, and the next person to
look would find a card that no recipe claims to have produced. It renders to
a temporary file and moves it into place once the render is known good.

The footer was placed at a fixed offset out of flow, so a longer headline
would have drawn the divider through the body copy with typst reporting
nothing. Flexible space pushes it down instead: the overflow spills onto a
second page, and a two-page render fails the PNG export outright.

Ran `just check`: passes. The card re-renders byte-identically after the
footer change, the recipe leaves the committed PNG untouched when the font
is missing, and a deliberately overlong headline fails the export.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The comment justified the og:image check by saying an unfurl is the surface
nobody on the team looks at. That is a claim about colleagues in a public
repository, and it is not what makes the check worth having. Says what the
failure actually looks like instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The hero comment credited two other companies' landing pages for the
decision to name the category in the first clause. The reasoning holds
without them, and a public repository is a poor place to record which
competitors were studied. Keeps the principle, drops the names.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`mktemp -t social-card` reserves a name, and the recipe then appended `.png`
to it — so typst wrote to a path nothing had reserved, the reserved file was
left behind empty on every run, and the trap cleaned up only the render. A
temporary directory reserves the whole name.

Also handles a relative `og:image` in the site check. The tag is hand-written
and someone could reasonably make it relative; Open Graph consumers do not
resolve those, and the check now says so rather than failing on a URL parse
error.

Ran `just check`: passes. `just social-card` re-renders the committed PNG
byte-identically.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vishr
vishr merged commit 0ae1183 into main Aug 24, 2026
5 checks passed
@vishr
vishr deleted the docs/repository-presentation branch August 24, 2026 14:29
vishr added a commit that referenced this pull request Aug 24, 2026
* docs: improve how the repository presents itself

Three gaps that all cost the project the same thing — someone finds Onebox
and leaves without understanding what it is or how to engage with it.

Issue and pull request templates. There were none, so a bug report arrived
without a version, a target host, or the plan output that shows the
discrepancy, and a proposal arrived without saying whether it widens the
one-application, one-host scope. The templates ask for exactly what a
maintainer needs on the first round trip, and the config points security
reports at SECURITY.md rather than a public issue.

A social preview card. GitHub and every chat client showed a generic grey
box for links to this repository. Worse, Starlight emits
`twitter:card: summary_large_image` and never an image to pair with it, so
links to onebox.run unfurled as an empty large card. The card is rendered
from `docs/media/social-card.typ`, and the site serves it as its og:image.

A comparison table. The README never named Docker Compose, Kamal, Dokku,
Coolify, Ansible, or Kubernetes, which are the words someone uses when they
are looking for a tool in this space. Each row states the boundary
difference rather than a feature score, and the Kubernetes row says plainly
what Onebox gives up.

Ran `just check`: passes. Did not run `just e2e`; nothing here touches the
binary or the deployment path.


* docs: gate the social card instead of trusting it

Review of the first commit found the card carrying two failure modes that
nothing would report.

The mark was copied into `docs/media/social-card-mark.svg`, byte-identical
to the one in `site/public/favicon.svg` and connected to it by nothing. The
favicon comment records that four earlier drafts of that mark died before
this one; the next revision would have reached the site and left the card —
the most-seen surface — drawing a retired logo. Typst reads the favicon
directly, so the copy is gone and the render is unchanged, pixel for pixel.

The PNG had no generator and no check. `just social-card` renders it, and
does the part a hand-typed command cannot: typst warns about an unknown font
family and still exits 0, so it verifies the font was actually found and
fails when it was not. The typst version is pinned because another release
re-lays out every glyph. CI has no font path and so cannot re-render, but
`site-build` now asserts the committed PNG exists and matches the dimensions
the head advertises — the previous commit emitted `og:image` unconditionally,
so renaming the asset would have left every page pointing at a 404.

Also corrects a comment from the previous commit: `astro.config.mjs` sets
`site` unconditionally, so the fallback is not a configuration this
repository ships.

Ran `just check`: passes. Exercised `just social-card` against an empty font
directory (fails, as intended) and a real one (renders a card identical to
the committed PNG), and `check-social-card.mjs` against a missing asset and
a wrong-sized one.


* docs: keep a bad card render out of the tree

Two parity fixes with the same change in the Fanout repository, where the
review that prompted them ran.

`just social-card` wrote straight to `site/public/social-card.png` and only
then checked whether typst had fallen back to a substitute face. It failed
correctly, but the wrong card was already on disk, and the next person to
look would find a card that no recipe claims to have produced. It renders to
a temporary file and moves it into place once the render is known good.

The footer was placed at a fixed offset out of flow, so a longer headline
would have drawn the divider through the body copy with typst reporting
nothing. Flexible space pushes it down instead: the overflow spills onto a
second page, and a two-page render fails the PNG export outright.

Ran `just check`: passes. The card re-renders byte-identically after the
footer change, the recipe leaves the committed PNG untouched when the font
is missing, and a deliberately overlong headline fails the export.


* docs: neutralise a comment about the team

The comment justified the og:image check by saying an unfurl is the surface
nobody on the team looks at. That is a claim about colleagues in a public
repository, and it is not what makes the check worth having. Says what the
failure actually looks like instead.


* docs: explain the tagline without naming other vendors

The hero comment credited two other companies' landing pages for the
decision to name the category in the first clause. The reasoning holds
without them, and a public repository is a poor place to record which
competitors were studied. Keeps the principle, drops the names.


* docs: stop the card recipe leaking a temp file

`mktemp -t social-card` reserves a name, and the recipe then appended `.png`
to it — so typst wrote to a path nothing had reserved, the reserved file was
left behind empty on every run, and the trap cleaned up only the render. A
temporary directory reserves the whole name.

Also handles a relative `og:image` in the site check. The tag is hand-written
and someone could reasonably make it relative; Open Graph consumers do not
resolve those, and the check now says so rather than failing on a URL parse
error.

Ran `just check`: passes. `just social-card` re-renders the committed PNG
byte-identically.


---------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant